using Microsoft.Extensions.DependencyInjection;
using SqlSugar;
using SqlSugar.IOC;

namespace DiLu.Expansion.DataStorage.SqlSugarExpansion;

/// <summary>
///     提供了扩展方法用于向ASP.NET Core依赖注入容器中注册SqlSugar服务及相关配置。
/// </summary>
public static class SqlSugarExpansionRegister
{
    /// <summary>
    ///     向服务集合中添加SqlSugarIoc扩展，配置数据库连接及相关设置。
    /// </summary>
    /// <typeparam name="TOperateAccountId">操作账户ID的类型。</typeparam>
    /// <param name="services">IServiceCollection实例，用于注册依赖注入服务。</param>
    /// <param name="connectionList">包含多个数据库连接配置的数组。</param>
    /// <param name="dataExecutingAction">一个可选的动作委托，用于在SQL执行前对数据进行过滤。</param>
    /// <param name="moreSettingAction">一个可选的动作委托，用于配置额外的连接设置。</param>
    /// <param name="moreSugarScopeProvider">一个可选的动作委托，允许进一步定制SqlSugarScopeProvider。</param>
    /// <exception cref="ArgumentNullException">当connectionList为null时抛出。</exception>
    /// <exception cref="ArgumentException">当没有提供任何DB配置或存在具有相同名称的数据库配置时抛出。</exception>
    public static void AddSqlSugarIocExpansion<TOperateAccountId>(this IServiceCollection services,
        SqlSugarConnectionConfig[] connectionList,
        Action<object, DataFilterModel> dataExecutingAction = null, Action<ConnMoreSettings> moreSettingAction = null,
        Action<SqlSugarScopeProvider> moreSugarScopeProvider = null)
    {
        ArgumentNullException.ThrowIfNull(connectionList, nameof(connectionList));
        if (connectionList.Length <= 0) throw new ArgumentException("没有任何DB配置");
        if (connectionList.GroupBy(o => o.Name.ToLower()).Any(o => o.Count() > 1))
            throw new ArgumentException("具有相同的数据库名称");

        services.AddSqlSugar(connectionList.Select(sqlSugarConfig => new IocConfig
        {
            ConfigId = sqlSugarConfig.Name,
            DbType = sqlSugarConfig.DbType,
            ConnectionString = sqlSugarConfig.ConnectionString,
            IsAutoCloseConnection = true
        }).ToList());

        services.ConfigurationSugar(sqlSugarDb =>
        {
            foreach (var connection in connectionList)
            {
                var sugarScopeProvider = sqlSugarDb.GetConnectionScope(connection.Name);
#if DEBUG
                //添加SQL执行前的事件，用于在SQL执行前记录日志
                sugarScopeProvider.AddLogExecuting(connection.Name);
#endif
                //添加SQL执行后的事件，用于在SQL执行后记录日志
                sugarScopeProvider.AddLogExecuted(connection.RecordLogSecond);

                //添加SQL执行后错误事件，用于在SQL执行出现错误时记录日志
                sugarScopeProvider.AddSqlErrorLog();

                //添加数据过滤器，在SQL执行前对数据进行过滤
                sugarScopeProvider.AddDataExecuting<TOperateAccountId>(dataExecutingAction);

                //更多连接设置
                var moreSettings = new ConnMoreSettings
                    { IsWithNoLockQuery = true, SqlServerCodeFirstNvarchar = true, IsNoReadXmlDescription = true };
                moreSettingAction?.Invoke(moreSettings);
                sugarScopeProvider.CurrentConnectionConfig.MoreSettings = moreSettings;

                //更多SqlSugar对象中间件服务
                moreSugarScopeProvider?.Invoke(sugarScopeProvider);
            }
        });

        var configs = connectionList.Select(o => new ConnectionConfig
        {
            ConfigId = o.Name,
            ConnectionString = o.ConnectionString,
            DbType = (DbType)o.DbType,
            IsAutoCloseConnection = true
        }).ToList();

        //注册ISqlSugarClient
        services.AddSingleton<ISqlSugarClient>(s =>
        {
            //单例不要写在泛型类中， 类<T>.Db 这种是无效单例 ，T不同就会有多个实例
            var db = new SqlSugarScope(configs,
                sqlSugarDb =>
                {
                    foreach (var connection in connectionList)
                    {
                        var sugarScopeProvider = sqlSugarDb.GetConnectionScope(connection.Name);
#if DEBUG
                        //添加SQL执行前的事件，用于在SQL执行前记录日志
                        sugarScopeProvider.AddLogExecuting(connection.Name);
#endif
                        //添加SQL执行后的事件，用于在SQL执行后记录日志
                        sugarScopeProvider.AddLogExecuted(connection.RecordLogSecond);

                        //添加SQL执行后错误事件，用于在SQL执行出现错误时记录日志
                        sugarScopeProvider.AddSqlErrorLog();

                        //添加数据过滤器，在SQL执行前对数据进行过滤
                        sugarScopeProvider.AddDataExecuting<TOperateAccountId>(dataExecutingAction);

                        //更多连接设置
                        var moreSettings = new ConnMoreSettings
                            { IsWithNoLockQuery = true, SqlServerCodeFirstNvarchar = true, IsNoReadXmlDescription = true };
                        moreSettingAction?.Invoke(moreSettings);
                        sugarScopeProvider.CurrentConnectionConfig.MoreSettings = moreSettings;

                        //更多SqlSugar对象中间件服务
                        moreSugarScopeProvider?.Invoke(sugarScopeProvider);
                    }
                });
            return db;
        });
    }
}